﻿/**@author 由W意波(LuoJun)编写*/
#ifndef LK_MUTEX_
#define LK_MUTEX_
#ifdef _LINUX
#include <pthread.h>
#endif

namespace LK
{
	/**
	@brief 互斥锁*/
	struct Mutex
	{
	private:
#ifdef _WINDOWS
		CRITICAL_SECTION cs;
#else
		pthread_mutex_t mutex;
		pthread_mutexattr_t attr;
		index_t id;
		index_t count;
#endif
		Mutex(const Mutex&);
		Mutex& operator=(const Mutex&);
	public:
		/**
		@brief 创建并初始化一个互斥锁*/
		Mutex();
		/**
		@brief 析构互斥锁*/
		~Mutex();
		/**
		@brief 上锁，如果该互斥锁被占用则始终等待*/
		void Lock();
		/**
		@brief 尝试上锁，并立即返回
		@return 如果不成功则立即返会false*/
		bool Try();
		/**
		@brief 解锁*/
		void UnLock();
		/**
		@brief 获取ID
		@return 返回值表示正在占用锁的线程id*/
		index_t GetID();
		/**
		@brief 获取进入次数
		@return 返回重复进入临界区的次数（应该要有相同的解锁次数）*/
		index_t GetCoutnt();
		/**
		@brief 重置*/
		void Reset();
		/**
		@brief 一个用于全局的默认锁*/
		static Mutex& GetDefaultRef();
	};
	/**
	@brief 单次互斥对象，同一个线程不可多次锁，速度要比Mutex快，但是等待时间较长时会消耗CPU资源*/
	struct SpinMutex
	{
#ifdef _WINDOWS
		long mlock;
#else
		pthread_mutex_t mutex;
#endif
		SpinMutex(const SpinMutex&);
		SpinMutex& operator=(const SpinMutex&);
	public:
		/**
		@brief 构造函数*/
		SpinMutex();
		/**
		@brief 析构函数*/
		~SpinMutex();
		/**
		@brief 一直等待直到上锁*/
		void Lock();
		/**
		@brief 尝试上锁并立即返回
		@return 成功返回true*/
		bool Try();
		/**
		@brief 解锁*/
		void UnLock();
		/**
		@brief 重置*/
		void Reset();
		/**
		@brief 获取一个全局静态的SpinMutex对象引用*/
		static SpinMutex& GetDefaultRef();
	};
	/**
	@brief 读写互斥对象，可多线程同时读取，但线程进行写入操作时将独占*/
	struct RWMutex
	{
#ifdef _WINDOWS
		volatile long wLock;
		volatile long rCount;
#else
		pthread_rwlock_t  mutex;
#endif
		RWMutex(const RWMutex&);
		RWMutex& operator=(const RWMutex&);
	public:
		/**
		@brief 默认构造函数*/
		RWMutex();
		/**
		@brief 析构函数*/
		~RWMutex();
		/**
		@brief 读操作，如果有写操作，将等待写操作完成*/
		void ReadLock();
		/**
		@brief 尝试读操作
		@return 成功返回true*/
		bool TryRead();
		/**
		@brief 释放读操作*/
		void ReadUnLock();
		/**
		@brief 进行写操作，该操作将阻止新的读操作进入并等待所有进行的读操作结束*/
		void WriteLock();
		/**
		@brief 尝试写操作
		@return 成功返回true*/
		bool TryWrite();
		/**
		@brief 释放写操作*/
		void WriteUnLock();
		/**
		@brief 重置*/
		void Reset();
		/**
		@brief 获取默认的读写锁*/
		static RWMutex& GetDefaultRef() { static RWMutex rw; return rw; }
	};
	/**
	@brief 启动线程的基础API*/
	index_t APIStartThread(void(*fun)(void*), void* param);
	/**
	@brief 获取当前线程的id*/
	index_t APIGetThreadID();
#ifdef _WINDOWS
	inline Mutex::Mutex() { InitializeCriticalSection(&this->cs); }
	inline Mutex::~Mutex() { DeleteCriticalSection(&this->cs); }
	inline void Mutex::Lock() { EnterCriticalSection(&this->cs); }
	inline bool Mutex::Try() { return TryEnterCriticalSection(&this->cs) != 0; }
	inline void Mutex::UnLock() { LeaveCriticalSection(&this->cs); }
	inline index_t Mutex::GetID() { return (index_t)this->cs.OwningThread; }
	inline index_t Mutex::GetCoutnt() { return (int)this->cs.LockCount; }
	inline void Mutex::Reset() { DeleteCriticalSection(&this->cs); InitializeCriticalSection(&this->cs); }

	/**
	@brief 等待线程id为dwThreadID的线程结束
	@param [传入]参数dwThreadID表示等待线程的ID
	@return 执行成功后返回调用结果*/
	inline u32 ThreadJoin(index_t dwThreadID)
	{
		HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)dwThreadID);  u32 result = WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); return result;
	}

	inline SpinMutex::SpinMutex() :mlock(0) {}
	inline void SpinMutex::Lock() {
		for (;;) {
#ifdef InterlockedCompareExchangePointer
			if (!InterlockedCompareExchange(&mlock, 1, 0))
				return;
#else
			if (!InterlockedCompareExchange((void**)&mlock, (void*)1, (void*)0))
				return;
#endif
			Sleep(0);
		}
	}
	inline bool SpinMutex::Try()
	{
#ifdef InterlockedCompareExchangePointer
		return !InterlockedCompareExchange(&mlock, 1, 0);
#else
		return !InterlockedCompareExchange((void**)&mlock, (void*)1, (void*)0);
#endif
	}
	inline void SpinMutex::UnLock()
	{
		InterlockedExchange(&mlock, 0);
	}
	inline SpinMutex::~SpinMutex() {}
	inline void SpinMutex::Reset() { mlock = 0; }

	inline RWMutex::RWMutex():wLock(0),rCount(0){}
	inline void RWMutex::ReadLock()
	{
	START:
		if (wLock != 0) { Sleep(0); goto START; }
		InterlockedIncrement(&rCount);
		if (wLock != 0) { InterlockedDecrement(&rCount); goto START; }
		return;
	}
	inline bool RWMutex::TryRead(){
		if (wLock != 0) { return false; }
		InterlockedIncrement(&rCount);
		if (wLock != 0) { InterlockedDecrement(&rCount); return false; }
		return true;
	}
	inline void RWMutex::ReadUnLock(){InterlockedDecrement(&rCount);}
	inline void RWMutex::WriteLock()
	{
		while(InterlockedCompareExchange(&wLock, 1, 0)!=0)Sleep(0);//等待写操作完成
		while (rCount != 0)Sleep(0);//等待读操作完成
		return;
	}
	inline bool RWMutex::TryWrite()
	{
		if (InterlockedCompareExchange(&wLock, 1, 0) != 0)return false;
		if (rCount != 0) { wLock = 0; return false; }
		return true;
	}
	inline void RWMutex::WriteUnLock() { wLock = 0; }
	inline void RWMutex::Reset() { rCount = wLock = 0; }
	inline RWMutex::~RWMutex() {}

#else
	inline DWORD ThreadJoin(DWORD threadid) { return pthread_join(threadid, NULL); }
	inline Mutex::Mutex() :id(0), count(0)
	{
		pthread_mutexattr_init(&attr);
		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
		pthread_mutex_init(&this->mutex, &attr);
	}
	inline Mutex::~Mutex() { pthread_mutex_destroy(&this->mutex); }
	inline void Mutex::Lock() { pthread_mutex_lock(&this->mutex); ++count; id = GetID(); }
	inline bool Mutex::Try() { if (pthread_mutex_trylock(&this->mutex) == 0) { ++count; id = GetID(); return true; } return false; }
	inline void Mutex::UnLock() { pthread_mutex_unlock(&this->mutex); if (--count == 0)id = 0; }
	inline index_t Mutex::GetID() { return id; }
	inline index_t Mutex::GetCoutnt() { return count; }
	inline void Mutex::Reset() { pthread_mutex_destroy(&this->mutex); pthread_mutex_init(&this->mutex, NULL); }

	inline SpinMutex::SpinMutex() { pthread_mutex_init(&this->mutex, NULL); }
	inline SpinMutex::~SpinMutex() { pthread_mutex_destroy(&this->mutex); }
	inline void SpinMutex::Lock() { pthread_mutex_lock(&this->mutex); }
	inline bool SpinMutex::Try() { return pthread_mutex_trylock(&this->mutex) == 0; }
	inline void SpinMutex::UnLock() { pthread_mutex_unlock(&this->mutex); }
	inline void SpinMutex::Reset() { pthread_mutex_destroy(&this->mutex); pthread_mutex_init(&this->mutex, NULL); }

	inline RWMutex::RWMutex() { if (pthread_rwlock_init(&mutex,NULL) != 0)Throw<PException>(L"读写锁初始化异常"); }
	inline RWMutex::~RWMutex() { if (pthread_rwlock_destroy(&mutex)!=0)Throw<PException>(L"读写锁销毁异常"); }
	inline void RWMutex::ReadLock() { if (pthread_rwlock_rdlock(&mutex) != 0)Throw<PException>(L"阻塞读锁获取异常"); }
	inline bool RWMutex::TryRead(){return pthread_rwlock_tryrdlock(&mutex)==0; }
	inline void RWMutex::ReadUnLock() { pthread_rwlock_unlock(&mutex); }
	inline void RWMutex::WriteLock(){if (pthread_rwlock_wrlock(&mutex) != 0)Throw<PException>(L"阻塞写锁获取异常");}
	inline bool RWMutex::TryWrite() { return pthread_rwlock_trywrlock(&mutex) ==0; }
	inline void RWMutex::WriteUnLock() { pthread_rwlock_unlock(&mutex); }
	inline void RWMutex::Reset() { pthread_rwlock_destroy(&mutex); pthread_rwlock_init(&mutex, NULL); }
#endif
}

#endif
